using Test
using FLEXINVERT
using FLEXINVERT.ForwardModel
using FLEXINVERT.PriorIO
using FLEXINVERT.CoreTypes
using FLEXINVERT.Settings
using FLEXINVERT.ObservationsCore
using FLEXINVERT.Footprints

@testset "Forward Model Tests" begin

    @testset "FluxField Construction" begin
        # Test basic FluxField creation
        lon = [1.0, 2.0, 3.0]
        lat = [4.0, 5.0]
        time = [0.0, 24.0]
        data = randn(3, 2, 2)

    flux = FluxField("test", data, lon, lat, time, "kg/m²/s", 1.0, nothing)

        @test flux.name == "test"
        @test size(flux.data) == (3, 2, 2)
        @test flux.scaling_factor == 1.0
        @test flux.units == "kg/m²/s"
    end

    @testset "PriorFluxes Construction" begin
        # Test PriorFluxes with some fields missing
        background = [420.0]
        fluxes = PriorFluxes(nothing, nothing, nothing, background, nothing, nothing, nothing)

        @test fluxes.nee === nothing
        @test fluxes.fossil_fuel === nothing
        @test fluxes.ocean === nothing
        @test fluxes.background == [420.0]
    end

    @testset "Forward Model - Background Only" begin
        # Create minimal test configuration
        config = Config(
            spec = "co2",
            datei = 20200301,
            datef = 20200302,
            w_edge_lon = 110.0,
            e_edge_lon = 116.0,
            s_edge_lat = 30.0,
            n_edge_lat = 36.0,
            xres = 0.5,
            yres = 0.5,
            average_fp = false,
            regions = false
        )

        domain = Domain(config)

        # Create test observations
        obs = ObservationsCore.empty_observations()
        ObservationsCore.add_observation!(obs, ObservationsCore.ObservationRecord(rec = "AAA", yyyymmdd = 20200301,
            hhmmss = 0, jdate = 1.0, avetime = 0.5, conc = 420.1, err = 0.05, num = 1);
            station_idx = 1, source_file = "test_obs_1")
        ObservationsCore.add_observation!(obs, ObservationsCore.ObservationRecord(rec = "AAA", yyyymmdd = 20200302,
            hhmmss = 0, jdate = 2.0, avetime = 0.5, conc = 420.2, err = 0.05, num = 2);
            station_idx = 1, source_file = "test_obs_2")

        # Test with background-only fluxes
        background = [420.0]
        fluxes = PriorFluxes(nothing, nothing, nothing, background, nothing, nothing, nothing)

        files = Files()
        footprints = Vector{Union{Nothing, FLEXINVERT.Footprints.FootprintData}}(fill(nothing, length(obs.concentrations)))
        y_mod = forward_model(config, domain, fluxes, obs; files = files, footprints = footprints)

        @test length(y_mod) == 2
        @test all(y_mod .== 420.0)  # Should match background
    end

    @testset "Background Concentration Reading" begin
        # Test fallback background concentration
        config = Config(
            spec = "co2",
            datei = 20200301,
            datef = 20200302,
            w_edge_lon = 110.0,
            e_edge_lon = 116.0,
            s_edge_lat = 30.0,
            n_edge_lat = 36.0,
            xres = 0.5,
            yres = 0.5
        )

        files = Files(
            file_recept = "",
            path_obs = "",
            suffix = "",
            path_output = ""
        )

        background = read_background_concentrations(files, config)
        @test length(background) == 1
        @test background[1] ≈ 0.0  # Default fallback when no background file provided
    end

    @testset "Model Concentration Calculation" begin
        config = Config(
            spec = "co2",
            datei = 20200301,
            datef = 20200302,
            w_edge_lon = 110.0,
            e_edge_lon = 116.0,
            s_edge_lat = 30.0,
            n_edge_lat = 36.0,
            xres = 0.5,
            yres = 0.5
        )

        domain = Domain(config)

        obs = ObservationsCore.empty_observations()
        ObservationsCore.add_observation!(obs, ObservationsCore.ObservationRecord(rec = "AAA", yyyymmdd = 20200301,
            hhmmss = 0, jdate = 1.0, avetime = 0.5, conc = 420.1, err = 0.05, num = 1);
            station_idx = 1, source_file = "test_obs")

        # Test with empty state vector
        state_vector = Float64[]
        y_mod = calculate_model_concentrations(config, domain, obs, state_vector)

        @test length(y_mod) == 1
        @test y_mod[1] == 0.0  # Should be zero with empty state vector

        # Test with non-empty state vector
        state_vector = [1.0, 2.0, 3.0]
        y_mod = calculate_model_concentrations(config, domain, obs, state_vector)

        @test length(y_mod) == 1
        @test y_mod[1] ≈ 0.02  # Should be small perturbation
    end
end
